
/*
 *  RnD_02_rolling_spheresTemplate.mm
 *  template
 *
 *  Created by SIO2 Interactive on 8/22/08.
 *  Copyright 2008 SIO2 Interactive. All rights reserved.
 *
 */

//File modified by Goffredo Marocchi (this is not the original SIO2 provided file,
//sio2 and its creator ROm are not responsible for the content of this file as it is now

#include "RnD_02_rolling_spheresTemplate.h"

#import "sio2.h"
#include "SysTools.h"
#import "RnD_02_rolling_spheresAppDelegate.h"

const GLfloat squareVertices[] = {
	-512.0f, -100.0f, 0.0f,
	512.0f,  -100.0f, 0.0f,
	-512.0f,  100.0f, 0.0f,
	512.0f,   100.0f, 0.0f
};
const GLubyte squareColors[] = {
	255, 255,   0, 255,
	0,   255, 255, 255,
	0,     0,   0,   0,
	255,   0, 255, 255,
};

extern id sio2GLView;

// Movement Direction ( Forward/Back ).
char  MOV_DIR = 0;

// Rotation Z.
float ROTZ = 0.0f;

// Rotation Direction ( Left/Right );
char ROTZ_DIR = 0;

// The smooth Z rotation component.
float SMOOTH_Z = 0.0f;

// Smooth Z attenuation factor.
float SMOOTH_FACTOR = 0.75f;

// The camera speed.
float SPEED = 0.0f;

// Touch screen sensitivity.
float SENSITIVITY = 5.0f;

// Handle to our SIO2mist structure
SIO2mist *_SIO2mist = NULL;

// Remember the origin of the light before
// transformation.
vec3 origin[ SIO2_LAMP_MAX ];

// Our physic & culling thread handle.
SIO2thread *_SIO2thread = NULL;

// Should we refresh the thread?
unsigned char refresh_thread = 1;

#define BULLET_DEBUG (0)

#if BULLET_DEBUG==1
/*********************/
#include "GLDebugDrawer.h"

GLDebugDrawer debugDrawer;
/*********************/
#endif

//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//////// template.mm functions                            ////////
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
unsigned char custom_parser( char *_root, char *_tok, char *_val )
{
	// Print the root value of the current struct as well as the
	// custom token and its value. In order to affect theses values
	// to existing variable I recommend you to use sio2StringScanf,
	// its mechanism is similar as sscanf but much faster. The 
	// supported type are:
	//
	// %s = char*
	// %f = float
	// %d = int
	// %c = unsigned char
	// %u = unsigned short
	//
	// For more information on how to use it please check the
	// any load function of the sio2 struct supported in the
	// file format like: sio2ObjectLoad, sio2CameraLoad etc...
	//
	printf("object: %s root:%s token:%s value:%s\n", sio2->_SIO2object->name, _root, _tok, _val );
	
	return 1;
}

void templateLoader (void) {
	
	static unsigned char loaded = 0;
	
	if( loaded == 0 )
	{
		unsigned int i = 0;
		
		loaded = 1;
		
		vec3 gravity;
		vec4 ambient_color;
		
		gravity.x =   0.0f;
		gravity.y =   0.0f;
		gravity.z = -10.0f;
		
		sio2->_SIO2physic = sio2PhysicInit((char *)"earth" );
		
		sio2PhysicSetGravity( sio2->_SIO2physic,
							 &gravity );
		
		sio2PhysicPlay( sio2->_SIO2physic );
		
#if BULLET_DEBUG==1
		//enable Physics debugging draw code
		debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe);
		sio2->_SIO2physic->_btSoftRigidDynamicsWorld->setDebugDrawer(&debugDrawer);
#endif
		
		sio2ResourceCreateDictionary( sio2->_SIO2resource );
		
		//sio2->_SIO2resource->_SIO2entry[ SIO2_OBJECT ].custom = custom_parser;
		
#if DEBUG==1
		NSLog (@"debug");
		sio2ResourceOpen( sio2->_SIO2resource,
						 "myBlend_debug.sio2", 1 );	
#else
		NSLog (@"release");
		sio2ResourceOpen( sio2->_SIO2resource,
						 "myBlend.sio2", 1 );
#endif
		
		
		while( i != sio2->_SIO2resource->gi.number_entry )
		{
			sio2ResourceExtract( sio2->_SIO2resource, NULL );
			++i;
		}
		
		sio2ResourceClose( sio2->_SIO2resource );
		sio2ResetState();
		
		sio2ResourceBindAllInstances(sio2->_SIO2resource);
		
		sio2ResourceBindAllImages( sio2->_SIO2resource );
		
		sio2ResourceBindAllMaterials( sio2->_SIO2resource );
		
		sio2ResourceBindAllMatrix( sio2->_SIO2resource );
		
		sio2ResourceBindAllPhysicObjects( sio2->_SIO2resource,
										 sio2->_SIO2physic );
		
		// Also generate the sound source buffer ID.
		sio2ResourceGenId( sio2->_SIO2resource );
		
		sio2->_SIO2camera = ( SIO2camera * )sio2ResourceGet( sio2->_SIO2resource,
															SIO2_CAMERA,
															"camera/Camera" );
		
		if( sio2->_SIO2camera )
		{
			sio2Perspective( sio2->_SIO2camera->fov,
							sio2->_SIO2window->scl->x / sio2->_SIO2window->scl->y,
							sio2->_SIO2camera->cstart,
							sio2->_SIO2camera->cend );
			
			sio2CameraGetProjectionMatrix( sio2->_SIO2camera );
		}
		
		i = 0;
		// Similar as the aproach abobe, here we loop for the number of
		// lamp held inside our resource manager, get the handle and record
		// the origin position of our lamp before transformation.
		while( i != sio2->_SIO2resource->n_lamp )
		{
			SIO2lamp *_SIO2lamp = ( SIO2lamp * )sio2->_SIO2resource->_SIO2lamp[ i ];
			
			origin[ i ].x = _SIO2lamp->_SIO2transform->loc->x;
			origin[ i ].y = _SIO2lamp->_SIO2transform->loc->y;
			origin[ i ].z = _SIO2lamp->_SIO2transform->loc->z; 
			
			++i;
		}
		// Set up the global ambient color of our scene. Please take note that
		// by default OpenGL set it to 0.0, 0.0, 0.0, 1.0 it is not really 
		// necessary to set it here, but its just for demonstration purpose.
		ambient_color.x = 0.0f;
		ambient_color.y = 0.0f;
		ambient_color.z = 0.0f;
		ambient_color.w = 1.0f;
		
		// Make the ambient color active.
		sio2LampSetAmbient( &ambient_color );
		
		// Increase the GL point size to render our light positions.
		glPointSize( 5.0f );
		
		sio2->_SIO2window->_SIO2windowrender = templateRender;
		
		//_SIO2thread = sio2ThreadInit();
	}
	/*if( sio2StringTok( sio2->sys, "iPod" ) )
	 {
	 sio2ThreadCreate( _SIO2thread,
	 templateCheckConnectionThread,
	 ( void * )sio2->_SIO2resource,
	 SIO2_THREAD_PRIORITY_VERY_HIGH );
	 }
	 else
	 {
	 sio2ThreadCreate( _SIO2thread,
	 templateCheckConnectionThread,
	 ( void * )sio2->_SIO2resource,
	 SIO2_THREAD_PRIORITY_HIGH );
	 }
	 sio2ThreadPlay( _SIO2thread );*/
	
	//[[sio2GLView getDelegate] connectionTest];
}

void templateRender2D( void )
{
	sio2WindowEnter2D( sio2->_SIO2window, 0.0f, 1.0f );
	{
		ALPHA_BLENDING_ON();
		
		// Standard GL calls...
		glVertexPointer( 3, GL_FLOAT, 0, squareVertices );
		glEnableClientState( GL_VERTEX_ARRAY );
		
		glColorPointer( 4, GL_UNSIGNED_BYTE, 0, squareColors );
		glEnableClientState( GL_COLOR_ARRAY );
		
		glPushMatrix();
		{
			// Get access to the current window width & height,
			// binded to the SIO2 structure and translate to
			// the middle of the screen.
			glTranslatef( sio2->_SIO2window->scl->x * 0.5f,
						 sio2->_SIO2window->scl->y * 0.5f, 0.0f );
			//glScalef(0.5f, 0.5f, 1.0f);
			
			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);	
		}
		glPopMatrix();
		[sio2GLView frame].size.width;
		
		ALPHA_BLENDING_OFF();
		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);
		
	}
	// Leave the 2D mode.
	sio2WindowLeave2D();}

void templateRender( void )
{	
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();
	glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT );
	glEnableClientState( GL_VERTEX_ARRAY);
	glEnableClientState( GL_TEXTURE_COORD_ARRAY );
	
	
	if( sio2->_SIO2camera )
	{
		sio2WindowEnterLandscape3D();
		{
			sio2CameraRender( sio2->_SIO2camera );
			sio2CameraGetModelviewMatrix( sio2->_SIO2camera );
			sio2CameraUpdateFrustum( sio2->_SIO2camera );
			sio2ResourceCull( sio2->_SIO2resource,
							 sio2->_SIO2camera );
			// Turn ON the mist
			//sio2MistRender( _SIO2mist );
			{
				unsigned int i = 0;
				//static float angle = 0.0f;
				while( i != sio2->_SIO2resource->n_lamp )
				{
					// Convert directly the void* to a SIO2lamp handle.
					SIO2lamp *_SIO2lamp = ( SIO2lamp * )sio2->_SIO2resource->_SIO2lamp[ i ];
					// Set the color to our current lamp
					glColor4f( _SIO2lamp->col->x,
							  _SIO2lamp->col->y,
							  _SIO2lamp->col->z,
							  _SIO2lamp->col->w );
					
					// Render a GL_POINT to represent the current position
					// of the Lamp in 3D space.
					glVertexPointer( 3, GL_FLOAT, 0, ( float * )_SIO2lamp->_SIO2transform->loc );
					glDrawArrays( GL_POINTS, 0, 1 );
					
					++i;
				}
				// Increment the Z angle to have a smooth rotation
				//angle += 1.0f;
				
				sio2LampEnableLight();
				bulletUpdate();
				sio2ResourceRender( sio2->_SIO2resource,
								   sio2->_SIO2window,
								   sio2->_SIO2camera,
								   SIO2_RENDER_SOLID_OBJECT | SIO2_RENDER_LAMP );
				sio2MaterialReset();
#if BULLET_DEBUG==1
				sio2->_SIO2physic->_btSoftRigidDynamicsWorld->debugDrawWorld();
#endif
				// Turn OFF the lights.
				sio2LampResetLight();
			}
			// Turn off the mist.
			sio2MistReset();
		}
		sio2WindowLeaveLandscape3D();
		
		templateRender2D();
		
	}
}



void templateShutdown( void )
{
	sio2ResourceUnloadAll( sio2->_SIO2resource );
	
	sio2->_SIO2resource = sio2ResourceFree( sio2->_SIO2resource );
	
	sio2->_SIO2window = sio2WindowFree( sio2->_SIO2window );
	
	sio2 = sio2Shutdown();
	
	printf("\nSIO2: shutdown...\n" );
}


// The coordinate of the original touch on the screen.
vec2 start;

void templateScreenTap( void *_ptr, unsigned char _state )
{
	// When we release the tap stop the
	// camera movements.
	if( _state == SIO2_WINDOW_TAP_UP )
	{ MOV_DIR = 0; }
	else
	{
		start.x = sio2->_SIO2window->touch[ 0 ]->x;
		start.y = sio2->_SIO2window->touch[ 0 ]->y;
	}
}


void templateScreenTouchMove( void *_ptr )
{
	/*
	 Calculate our movement direction based
	 on the delta of our touchscreen initial
	 point and current point.
	 */
	
	vec2 d;
	d.y = sio2->_SIO2window->touch[ 0 ]->x - start.x;
	d.x = start.y - sio2->_SIO2window->touch[ 0 ]->y;
	
	if( d.x > 5.0f )
	{
		MOV_DIR = -1;
		SPEED = ( d.x * 0.025f );
	}
	else if( d.x < -5.0f )
	{
		MOV_DIR = 1;		
		SPEED = -( d.x * 0.025f );
	}
	
	
#ifdef USE_SIMULATOR
	
	// If we got a movement from the device
	// between theses 2 thresholds.
	if( d.y > 5.0f || d.y < -5.0f )
	{
		// Use the Y axis of the accelerometer
		// for camera Z rotation.
		float tmp = d.y * SENSITIVITY * 0.001f;
		
		if( d.y > 0.0 )
		{ ROTZ_DIR = -1; }
		else if( d.y < 0.0 )
		{ ROTZ_DIR = 1; }
		
		if( abs( tmp ) > abs( SMOOTH_Z ) )
		{ SMOOTH_Z = abs( tmp ) * SMOOTH_FACTOR; }
		
		ROTZ -= tmp;
	}
#endif
}


void templateScreenAccelerometer( void *_ptr )
{
#ifndef USE_SIMULATOR
	
	// If we got a movement from the device
	// between theses 2 thresholds.
	if( sio2->_SIO2window->accel->y > 0.1f || sio2->_SIO2window->accel->y < -0.1f )
	{
		// Use the Y axis of the accelerometer
		// for camera Z rotation.
		float tmp = sio2->_SIO2window->accel->y * SENSITIVITY;
		
		if( sio2->_SIO2window->accel->y > 0.0 )
		{ ROTZ_DIR = -1; }
		else if( sio2->_SIO2window->accel->y < 0.0 )
		{ ROTZ_DIR = 1; }
		
		if( abs( tmp ) > abs( SMOOTH_Z ) )
		{ SMOOTH_Z = abs( tmp ) * SMOOTH_FACTOR; }
		
		ROTZ -= tmp;
	}
	
#endif
}

void bulletUpdate( void ) {
	
	// Just to show that we can use the physic render
	// function at different location and adjust the
	// sequence according to the type of structure that
	// we want to achieve.
	sio2PhysicRender( sio2->_SIO2physic,
					 sio2->_SIO2window->d_time, 4 );
	
}

void renderLights( void ) {
	
	unsigned int i = 0;
	
	// Remember our last angle value.
	static float angle = 0.0f;
	
	// Here Im introducing a new way to get access to an handle inside
	// the resource manager. Im not using the helper sio2ResourceGet but
	// go directly to search the pointer to all the current SIO2lamp 
	// contained in the main SIO2resource.
	while( i != sio2->_SIO2resource->n_lamp )
	{
		// Convert directly the void* to a SIO2lamp handle.
		SIO2lamp *_SIO2lamp = ( SIO2lamp * )sio2->_SIO2resource->_SIO2lamp[ i ];
		
		// Function to calculate a vertex in 3D space passing
		// the origin point, the X angle and the Z angle as well
		// as how far we want the new point to be.
		sio2Rotate3D( &origin[ i ],
					 25.0f,
					 angle,
					 15.0f,
					 _SIO2lamp->_SIO2transform->loc );
		
		// Set the color to our current lamp
		glColor4f( _SIO2lamp->col->x,
				  _SIO2lamp->col->y,
				  _SIO2lamp->col->z,
				  _SIO2lamp->col->w );
		
		// Render a GL_POINT to represent the current position
		// of the Lamp in 3D space.
		glVertexPointer( 3, GL_FLOAT, 0, ( float * )_SIO2lamp->_SIO2transform->loc );
		glDrawArrays( GL_POINTS, 0, 1 );
		
		++i;
	}
	// Increment the Z angle to have a smooth rotation
	angle += 1.0f;
	
	// Enable GL_LIGTHING and setup the necessary
	// state variables to render our objects with
	// lights & materials applied.
	sio2LampEnableLight();
	{
		sio2ResourceRender( sio2->_SIO2resource,
						   sio2->_SIO2window,
						   sio2->_SIO2camera,
						   SIO2_RENDER_SOLID_OBJECT | SIO2_RENDER_LAMP );
		
		sio2MaterialReset();
	}
	// Turn OFF the lights.
	sio2LampResetLight();
	
}

